/*
*    Phantom Test Driver v2.0 GUI Automation Software
*    Copyright (C) 2009  John C. Van Arsdall (john@phantomtest.com)
*
*    This program is free software; you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation; either version 2 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License along
*    with this program; if not, write to the Free Software Foundation, Inc.,
*    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*//*
 * SSI_Socket.java
 *
 * Created on September 28, 2005, 9:51 PM
 *
 * To change this template, choose Tools | Options and locate the template under
 * the Source Creation and Management node. Right-click the template and choose
 * Open. You can then make changes to the template in the Source Editor.
 */

package ssi_socket;

import java.net.*;
import java.io.*;
import java.nio.ByteBuffer;
import ptd.Main;
/**
 *
 * @author John
 */

/*
int SSI_OPEN_REQUEST = 131;
#define  SSI_LINE_REQUEST      132
#define  SSI_RESPONSE_OUTPUT   133
#define  SSI_COMMAND           134
#define  SSI_BYE               135
*/

/*
#define  SSI_OPEN_REQUEST      131
#define  SSI_LINE_REQUEST      132
#define  SSI_RESPONSE_OUTPUT   133
#define  SSI_COMMAND           134
#define  SSI_BYE               135
#define  SSI_ACTION_REQUEST    136
#define  SSI_ACTION_RESPONSE   137

#define  SSI_ERROR_OUTPUT      140
#define  SSI_WARNING_OUTPUT    141
#define  SSI_FAILURE_OUTPUT    142

#define  SSI_RSP_PORT          200

#define  SSI_VAR_RQST          300
#define  SSI_VAR_RSP           301

#define  SSI_DBG_RQST          500
#define  SSI_DBG_RSP           501
#define  SSI_DBG_STEP          510

#define  SSI_BPT_ADD           520
#define  SSI_BPT_RMV           521

#define  SSI_DBG_JMP           530
#define  SSI_DBG_OUT           531

#define  SSI_DBG_EVAL          540

#define  SSI_DBG_GOCTR         550
#define  SSI_DBG_TOLIN         551
*/

public class SSI_Socket {
    
    public Socket MySocket;
    //public InputStream in;
    //public OutputStream out;

    public DataInputStream in;
    public DataOutputStream out;

    //public BufferedInputStream in;
    //public BufferedOutputStream out;

    
    public String lastError;
    /** Creates a new instance of SSI_Socket */
    public SSI_Socket() {
        lastError = new String();
        lastError = "None";
    }
    
    //public ~SSI_Socket(){
    //    if(MySocket.isConnected()){
    //        MySocket.close();
    //    }
    //}
    
    public static int SSI_OPEN_REQUEST     = 131;
    public static int SSI_LINE_REQUEST     = 132;
    public static int SSI_RESPONSE_OUTPUT  = 133;
    public static int SSI_COMMAND          = 134;
    public static int SSI_BYE              = 135;
    public static int SSI_ACTION_REQUEST   = 136;
    public static int SSI_ACTION_RESPONSE  = 137;
  
    public static int SSI_ERROR_OUTPUT     = 140;
    public static int SSI_WARNING_OUTPUT   = 141;
    public static int SSI_FAILURE_OUTPUT   = 142;
    
    public static int SSI_RSP_PORT         = 200;
    public static int SSI_FLAG_REQUEST     = 210;
    public static int SSI_FLAG_RESPONSE    = 211;
    
    public static int RSP_ERROR            = 2;
    public static int RSP_ACK              = 1;
    public static int RSP_NACK             = 0;

    public static int SSI_VAR_RQST         = 300;
    public static int SSI_VAR_RSP          = 301;

    public static int SSI_DBG_RQST         = 500;
    public static int SSI_DBG_RSP          = 501;
    public static int SSI_DBG_STEP         = 510;

    public static int SSI_BPT_ADD          = 520;
    public static int SSI_BPT_RMV          = 521;

    public static int SSI_DBG_JMP          = 530;
    public static int SSI_DBG_OUT          = 531;

    public static int SSI_DBG_EVAL         = 540;

    public static int SSI_DBG_GOCTR        = 550;
    public static int SSI_DBG_TOLIN        = 551;
    
    public int Connect(String pcHost, int Port){
        try{
            InetAddress anAddr = InetAddress.getByName(pcHost);
            //MySocket = new Socket(anAddr, Port);
            //SocketAddress sockAddr = new SocketAddress();
            //sockAddr.
            MySocket = new Socket();
            MySocket.connect(new InetSocketAddress(anAddr, Port));
            //MySocket.bind(new InetSocketAddress(anAddr, Port));
            //MySocket = new Socket(anAddr, Port, InetAddress.getLocalHost(), 4242);
            //in = MySocket.getInputStream();
            //out = MySocket.getOutputStream();            
            
            // What about buffered streams?
            in = new DataInputStream(MySocket.getInputStream());
            out = new DataOutputStream(MySocket.getOutputStream());
            
            //in = new BufferedInputStream(MySocket.getInputStream());
            //out = new BufferedOutputStream(MySocket.getOutputStream());
            
        }catch (UnknownHostException e){
            Main.debug_out(e.getMessage());
            return 0;
        }catch (IOException e){
            Main.debug_out(e.getMessage());
            return 0;
        }
       
        return 1;
    }
    
    public int Close(){
        try{
            MySocket.shutdownInput();
            MySocket.shutdownOutput();
            MySocket.close();
        }catch (Exception e){
            Main.debug_out(e.getMessage());
            return 0;
        }
        return 1;
    }
    
    /*
    public int SendCommand(SSI_SockCmd aCmd){

        byte[] sData;
        if(aCmd.Data != null){
            sData = aCmd.Data.getBytes();
        }else{
            sData = new byte[1];
            sData[0] = 0;
        }
        
        try{
            // you *can* write int, write int, write string...
            ByteBuffer b = ByteBuffer.allocate(4);
            b.putInt(aCmd.ID);
            
            byte[] bb = b.array();
            out.write(bb[3]);
            out.write(bb[2]);
            out.write(bb[1]);
            out.write(bb[0]);
           
            // It is stupid, but you cant write an int... must flip the byte order too
            // Write connection ID
            b.clear();
            b.putInt(aCmd.ConnectionID);
            bb = b.array();
            
            out.write(bb[3]);
            out.write(bb[2]);
            out.write(bb[1]);
            out.write(bb[0]);

            // Write sequence counter
            b.clear();
            b.putInt(aCmd.SequenceCtr);
            bb = b.array();
            
            out.write(bb[3]);
            out.write(bb[2]);
            out.write(bb[1]);
            out.write(bb[0]);

            // Write Size
            b.clear();
            b.putInt(aCmd.Size);
            bb = b.array();
            
            out.write(bb[3]);
            out.write(bb[2]);
            out.write(bb[1]);
            out.write(bb[0]);

            if(aCmd.Size > 0){
                out.write(sData);
            }
            
        }catch(IOException e){
            Main.debug_out(e.getMessage());
            lastError = e.getMessage();
            return 0;
        }
        
        return 1;
    }
     */

/*    
    public SSI_SockCmd ReadCommand(){
        SSI_SockCmd Ret = new SSI_SockCmd();
        
        int RSP_ERROR = 0;
        int OldCtr = Ret.SequenceCtr;
        
        try{
            // to read an int
            //ByteBuffer b = ByteBuffer.allocate(4);  //new ByteBuffer();
   
            byte[] Data = new byte[4];
            //byte[] Rev = new byte[4];
            
            // Read the Command ID
            if(in.read(Data) != 4){
                lastError = "SSI_Socket: Read data differs from expected size (4)";
                Ret.ID = RSP_ERROR;
                return Ret;
            }
            Ret.ID = IntFromBytes(Data);
            
            // Read the connection ID
            if(in.read(Data) != 4){
                lastError = "SSI_Socket: Read data differs from expected size (4)";
                Ret.ID = RSP_ERROR;
                return Ret;
            }
            Ret.ConnectionID = IntFromBytes(Data);

            // Read the sequence counter
            if(in.read(Data) != 4){
                lastError = "SSI_Socket: Read data differs from expected size (4)";
                Ret.ID = RSP_ERROR;
                return Ret;
            }
            Ret.SequenceCtr = IntFromBytes(Data);


//            Rev[0] = Data[3];
//            Rev[1] = Data[2];
//            Rev[2] = Data[1];
//            Rev[3] = Data[0];
//            b.clear();
//            b.put(Rev, 0, 4);            
//            Ret.ID = b.getInt(0);

            if(in.read(Data) != 4){
                lastError = "SSI_Socket: Read data differs from expected size (4)";
                Ret.ID = RSP_ERROR;
                return Ret;
            }
            Ret.Size = IntFromBytes(Data);

            // Read the Command String
            Data = new byte[Ret.Size];
            if(in.read(Data) != Ret.Size){
                lastError = "SSI_Socket: Read data differs from expected size";
                Ret.ID = RSP_ERROR;
                return Ret;
            }
            Ret.Data = new String(Data);

            if(Ret.SequenceCtr != OldCtr){
                Ret.bValidSequence = false;
            }else{
                Ret.bValidSequence = true;
            }
            Ret.SequenceCtr = Ret.SequenceCtr + 1;
            
            
        }catch(IOException e){
            lastError = e.getMessage();
            Ret.ID = RSP_ERROR;
            return Ret;
        }
        
        return Ret;
    }
 **/
    
     public static int IntFromString(String s){
         int Ret;
         ByteBuffer b = ByteBuffer.allocate(4);  //new ByteBuffer();
         byte[] Data = s.getBytes();
         return IntFromBytes(Data);
     }    
     
     public static int IntFromBytes(byte[] Data){
         int Ret;
         byte[] Rev = new byte[4];
         ByteBuffer b = ByteBuffer.allocate(4);  //new ByteBuffer();
         if(Data.length < 4){
             return 0;
         }
         
         Rev[0] = Data[3];
         Rev[1] = Data[2];
         Rev[2] = Data[1];
         Rev[3] = Data[0];
         
         b.clear();
         b.put(Rev, 0, 4);
            
         Ret = b.getInt(0);
         return Ret;
     } 

     public static String StringFromInt(int i){
         String Ret;
         ByteBuffer b = ByteBuffer.allocate(4);  //new ByteBuffer();
         b.putInt(i);
         byte[] Data = b.array();         
         byte[] Rev = new byte[4];
         
         Rev[0] = Data[3];
         Rev[1] = Data[2];
         Rev[2] = Data[1];
         Rev[3] = Data[0];

         Ret = new String(Rev);
         return Ret;
     }    

     
     public int writeInt(int In) throws IOException{
         ByteBuffer b = ByteBuffer.allocate(4);
         b.clear();
         b.putInt(In);
         byte[] bb = b.array();
         byte[] bb2 = bb.clone();
         bb[0] = bb2[3];
         bb[1] = bb2[2];
         bb[2] = bb2[1];
         bb[3] = bb2[0];
         
         out.write(bb, 0, 4);
 
         // For some reason this was no longer accurate (wrote 5 bytes instead of 4)
         //out.write(bb[3]);
         //out.write(bb[2]);
         //out.write(bb[1]);
         //out.write(bb[0]);
         
         return 1;
     }
     
     public static String getHostName(){
        try {
            return InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException e) {
            return "unknown";
        }
     }

}

